﻿using ICSharpCode.SharpZipLib.Zip;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;

namespace Learun.Application.Web.Common
{
    /// <summary>
    /// KML实体
    /// </summary>
    public class Placemark
    {
        public string name { get; set; }
        public string typeStr { get; set; }
        public List<double> points { get; set; }
        public object style { get; set; }
        public List<Coordinates> coordinates { get; set; }
    }
    /// <summary>
    /// 坐标
    /// </summary>
    public class Coordinates
    {
        public double X { get; set; }
        public double Y { get; set; }
        public double Z { get; set; }
    }

    public class KmlUtility
    {

        /// <summary>  
        /// 解压缩文件(压缩文件中含有子目录)  
        /// </summary>  
        /// <param name="zipfilepath">待解压缩的文件路径</param>  
        /// <param name="unzippath">解压缩到指定目录</param>  
        /// <returns>解压后的文件列表</returns>  
        public static List<string> UnZip(string zipfilepath, string unzippath)
        {
            if (!File.Exists(zipfilepath))
            {
                return new List<string>();
            }
            //解压出来的文件列表  
            List<string> unzipFiles = new List<string>();

            //检查输出目录是否以“\\”结尾  
            List<string> kmlfile = new List<string>();
            if (unzippath.EndsWith("\\") == false || unzippath.EndsWith(":\\") == false)
            {
                unzippath += "\\";
            }
            ZipInputStream s = new ZipInputStream(File.OpenRead(zipfilepath));
            ZipEntry theEntry;
            while ((theEntry = s.GetNextEntry()) != null)
            {
                if (Path.GetExtension(theEntry.Name).ToLower() == ".kml")
                {
                    string directoryName = Path.GetDirectoryName(unzippath);
                    string fileName = Path.GetFileName(theEntry.Name);

                    //生成解压目录【用户解压到硬盘根目录时，不需要创建】  
                    if (!string.IsNullOrEmpty(directoryName))
                    {
                        Directory.CreateDirectory(directoryName);
                    }
                    if (fileName != String.Empty)
                    {
                        //如果文件的压缩后大小为0那么说明这个文件是空的,因此不需要进行读出写入  
                        if (theEntry.CompressedSize == 0)
                            continue;
                        //解压文件到指定的目录  
                        directoryName = Path.GetDirectoryName(unzippath + theEntry.Name);
                        //建立下面的目录和子目录  
                        Directory.CreateDirectory(directoryName);

                        kmlfile.Add(unzippath + theEntry.Name);
                        //记录导出的文件  
                        unzipFiles.Add(unzippath + theEntry.Name);

                        FileStream streamWriter = File.Create(unzippath + theEntry.Name);

                        int size = 2048;
                        byte[] data = new byte[2048];
                        while (true)
                        {
                            size = s.Read(data, 0, data.Length);
                            if (size > 0)
                            {
                                streamWriter.Write(data, 0, size);
                            }
                            else
                            {
                                break;
                            }
                        }

                        streamWriter.Close();
                    }
                }

            }
            s.Close();
            GC.Collect();
            return kmlfile;
        }

        /// <summary>
        /// 获取kml对象
        /// </summary>
        /// <param name="kmlPath"></param>
        /// <returns></returns>
        public static List<Placemark> readKml(string kmlPath, bool isAPP = false)
        {
            List<string> list = new List<string>();
            List<Placemark> retMarks = new List<Placemark>();
            if (!File.Exists(kmlPath))
            {
                return new List<Placemark>();
            }
            if (Path.GetExtension(kmlPath).ToLower() == ".kmz")
            {
                list = UnZip(kmlPath, Path.GetDirectoryName(kmlPath));
            }
            else
            {
                list.Add(kmlPath);
            }
            foreach (var path in list)
            {
                XmlDocument xmldoc = new XmlDocument();
                xmldoc.Load(path);
                //申明xml命名空间管理对象
                XmlNamespaceManager nsmanager = new XmlNamespaceManager(xmldoc.NameTable);
                XmlElement root = xmldoc.DocumentElement;
                //添加命名空间
                nsmanager.AddNamespace("XX", "" + root.NamespaceURI + "");
                /////规范命名空间
                XmlNode t = root.GetElementsByTagName("Kml")[0];
                XmlNode _document = root.GetElementsByTagName("Document")[0];
                // XmlNodeList xmlmark = root.GetElementsByTagName("Placemark");
                XmlNodeList xmlmark = xmldoc.SelectNodes("//XX:Placemark", nsmanager);
                int tpid = 0;//踏勘点序号  
                foreach (XmlElement element in xmlmark)
                {
                    Placemark mark = new Placemark();
                    mark.points = new List<double>();
                    tpid = tpid + 1;
                    string note = "";
                    var nameNode = element.GetElementsByTagName("name");
                    if (nameNode != null && nameNode.Count > 0)
                    {
                        string nmNode = nameNode[0].InnerText;
                        note = nmNode.Trim();
                    }
                    mark.name = note;
                    XmlElement cNode = null;
                    var pointNode = element.GetElementsByTagName("Point");
                    if (pointNode != null && pointNode.Count > 0)
                    {
                        mark.typeStr = "point";
                        cNode = (XmlElement)pointNode[0];
                    }
                    else
                    {
                        var lineNode = element.GetElementsByTagName("LineString");
                        if (lineNode != null && lineNode.Count > 0)
                        {
                            mark.typeStr = "line";
                            cNode = (XmlElement)lineNode[0];
                        }
                        else
                        {
                            continue;
                        }
                    }
                    var coordinatesNode = cNode.GetElementsByTagName("coordinates");
                    if (coordinatesNode != null && coordinatesNode.Count > 0)
                    {
                        string pointstr = coordinatesNode[0].InnerText;
                        var points = pointstr.Split(new char[] { '\n', ' ' });
                        var pointsCount = points.Length;
                        int pIndex = -1;
                        foreach (var item in points)
                        {
                            pIndex++;
                            if (pointsCount > 50)
                            {
                                if (isAPP && pIndex != 0 && pIndex != pointsCount - 1)
                                {
                                    var yu = pIndex % 4;
                                    if (yu != 0)
                                    {
                                        continue;
                                    }
                                }
                            }
                            var pointStr = item.Trim();
                            if (string.IsNullOrEmpty(pointStr))
                            {
                                continue;
                            }
                            var point = pointStr.Split(',');
                            if (point.Length < 3)
                            {
                                continue;
                            }
                            double X = Convert.ToDouble(point[0].Trim());
                            double Y = Convert.ToDouble(point[1].Trim());
                            mark.points.Add(X);
                            mark.points.Add(Y);
                        }
                    }
                    //线必须大于两个点
                    if (mark.points.Count < 4 && (mark.points.Count % 2) != 0 && mark.typeStr == "line")
                    {
                        continue;
                    }
                    if (mark.points.Count > 0)
                    {
                        retMarks.Add(mark);
                    }
                }
            }

            return retMarks;
        }

        /// <summary>
        /// 获取kml对象
        /// </summary>
        /// <param name="kmlPath"></param>
        /// <returns></returns>
        public static List<Placemark> readzKml(string kmlPath, bool isAPP = false)
        {
            List<string> list = new List<string>();
            List<Placemark> retMarks = new List<Placemark>();
            if (!File.Exists(kmlPath))
            {
                return new List<Placemark>();
            }
            if (Path.GetExtension(kmlPath).ToLower() == ".kmz")
            {
                list = UnZip(kmlPath, Path.GetDirectoryName(kmlPath));
            }
            else
            {
                list.Add(kmlPath);
            }
            foreach (var path in list)
            {
                XmlDocument xmldoc = new XmlDocument();
                xmldoc.Load(path);
                //申明xml命名空间管理对象
                XmlNamespaceManager nsmanager = new XmlNamespaceManager(xmldoc.NameTable);
                XmlElement root = xmldoc.DocumentElement;
                //添加命名空间
                nsmanager.AddNamespace("XX", "" + root.NamespaceURI + "");
                /////规范命名空间
                XmlNode t = root.GetElementsByTagName("Kml")[0];
                XmlNode _document = root.GetElementsByTagName("Document")[0];
                // XmlNodeList xmlmark = root.GetElementsByTagName("Placemark");
                XmlNodeList xmlmark = xmldoc.SelectNodes("//XX:Placemark", nsmanager);
                int tpid = 0;//踏勘点序号  
                foreach (XmlElement element in xmlmark)
                {
                    Placemark mark = new Placemark();
                    mark.points = new List<double>();
                    tpid = tpid + 1;
                    string note = "";
                    var nameNode = element.GetElementsByTagName("name");
                    if (nameNode != null && nameNode.Count > 0)
                    {
                        string nmNode = nameNode[0].InnerText;
                        note = nmNode.Trim();
                    }
                    mark.name = note;
                    XmlElement cNode = null;
                    var pointNode = element.GetElementsByTagName("Point");
                    var lineString = element.GetElementsByTagName("LineString");
                    var linearRing = element.GetElementsByTagName("LinearRing");
                    if (pointNode != null && pointNode.Count > 0)
                    {
                        mark.typeStr = "point";
                        cNode = (XmlElement)pointNode[0];
                    }
                    else if (lineString != null && lineString.Count > 0)
                    {

                        mark.typeStr = "line";
                        cNode = (XmlElement)lineString[0];

                    }
                    else if (linearRing != null && linearRing.Count > 0)
                    {
                        mark.typeStr = "ring";
                        cNode = (XmlElement)linearRing[0];
                    }
                    else
                    {
                        continue;
                    }
                    var coordinatesNode = cNode.GetElementsByTagName("coordinates");
                    if (coordinatesNode != null && coordinatesNode.Count > 0)
                    {
                        string pointstr = coordinatesNode[0].InnerText;
                        var points = pointstr.Split(new char[] { '\n', ' ' });
                        var pointsCount = points.Length;
                        int pIndex = -1;
                        foreach (var item in points)
                        {
                            pIndex++;
                            var pointStr = item.Trim();
                            if (string.IsNullOrEmpty(pointStr))
                            {
                                continue;
                            }
                            var point = pointStr.Split(',');
                            if (point.Length < 3)
                            {
                                continue;
                            }
                            double X = Convert.ToDouble(point[0].Trim());
                            double Y = Convert.ToDouble(point[1].Trim());
                            double Z = Convert.ToDouble(point[2].Trim());
                            if (mark.typeStr == "line")
                            {
                                Z += 100;
                            }
                            mark.points.Add(X);
                            mark.points.Add(Y);
                            mark.points.Add(Z);
                        }
                    }
                    //线必须大于两个点
                    if (mark.points.Count < 6 && (mark.points.Count % 3) != 0 && mark.typeStr == "line")
                    {
                        continue;
                    }
                    if (mark.points.Count > 0)
                    {
                        retMarks.Add(mark);
                    }
                }
            }
            return retMarks;
        }

        /// <summary>
        /// 获取kml对象
        /// </summary>
        /// <param name="kmlPath"></param>
        /// <returns></returns>
        public static List<Placemark> readzKml(string kmlPath)
        {
            List<string> list = new List<string>();
            List<Placemark> retMarks = new List<Placemark>();
            if (!File.Exists(kmlPath))
            {
                return new List<Placemark>();
            }
            if (Path.GetExtension(kmlPath).ToLower() == ".kmz")
            {
                list = UnZip(kmlPath, Path.GetDirectoryName(kmlPath));
            }
            else
            {
                list.Add(kmlPath);
            }
            foreach (var path in list)
            {
                XmlDocument xmldoc = new XmlDocument();
                xmldoc.Load(path);
                //申明xml命名空间管理对象
                XmlNamespaceManager nsmanager = new XmlNamespaceManager(xmldoc.NameTable);
                XmlElement root = xmldoc.DocumentElement;
                //添加命名空间
                nsmanager.AddNamespace("XX", "" + root.NamespaceURI + "");
                /////规范命名空间
                XmlNode t = root.GetElementsByTagName("Kml")[0];
                XmlNode _document = root.GetElementsByTagName("Document")[0];
                XmlNodeList xmlmark = xmldoc.SelectNodes("//XX:Placemark", nsmanager);
                foreach (XmlElement element in xmlmark)
                {
                    Placemark mark = new Placemark();
                    mark.coordinates = new List<Coordinates>();
                    string note = "";
                    var nameNode = element.GetElementsByTagName("name");
                    if (nameNode != null && nameNode.Count > 0)
                    {
                        string nmNode = nameNode[0].InnerText;
                        note = nmNode.Trim();
                    }
                    mark.name = note;
                    string IconStyleColor = "";
                    string LabelStyleColor = "";
                    string LineStyleColor = "";
                    string LineStyleWidth = "";
                    var styleNode = element.GetElementsByTagName("Style");
                    if (styleNode != null && styleNode.Count > 0)
                    {
                        XmlElement tempStyleNode = (XmlElement)styleNode[0];
                        //图标样式
                        var iconStyle = tempStyleNode.GetElementsByTagName("IconStyle");
                        if (iconStyle != null && iconStyle.Count > 0)
                        {
                            XmlElement iconStyleNode = (XmlElement)iconStyle[0];
                            var color = iconStyleNode.GetElementsByTagName("color");
                            IconStyleColor = color[0].InnerText.Trim();
                        }
                        //标签样式
                        var labelStyle = tempStyleNode.GetElementsByTagName("LabelStyle");
                        if (iconStyle != null && iconStyle.Count > 0)
                        {
                            XmlElement labelStyleNode = (XmlElement)labelStyle[0];
                            var color = labelStyleNode.GetElementsByTagName("color");
                            LabelStyleColor = color[0].InnerText.Trim();
                        }
                        //线样式
                        var lineStyle = tempStyleNode.GetElementsByTagName("LineStyle");
                        if (lineStyle != null && lineStyle.Count > 0)
                        {
                            XmlElement lineStyleNode = (XmlElement)lineStyle[0];
                            var lineStyleColor = lineStyleNode.GetElementsByTagName("color");
                            LineStyleColor = lineStyleColor[0].InnerText.Trim();
                            var width = lineStyleNode.GetElementsByTagName("width");
                            LineStyleWidth = width[0].InnerText.Trim();
                        }
                    }
                    XmlElement cNode = null;
                    var pointNode = element.GetElementsByTagName("Point");
                    var lineString = element.GetElementsByTagName("LineString");
                    var linearRing = element.GetElementsByTagName("LinearRing");
                    if (pointNode != null && pointNode.Count > 0)
                    {
                        mark.typeStr = "point";
                        foreach (var p in pointNode)
                        {
                            cNode = (XmlElement)p;
                            //点的样式
                            mark.style = new { IconStyleColor, LabelStyleColor };
                            var coordinatesNode = cNode.GetElementsByTagName("coordinates");
                            if (coordinatesNode != null && coordinatesNode.Count > 0)
                            {
                                string pointstr = coordinatesNode[0].InnerText;
                                var points = pointstr.Split(new char[] { '\n', ' ' });
                                var pointsCount = points.Length;
                                foreach (var item in points)
                                {
                                    var coordinates = new Coordinates();
                                    var pointStr = item.Trim();
                                    if (string.IsNullOrEmpty(pointStr))
                                    {
                                        continue;
                                    }
                                    var point = pointStr.Split(',');
                                    double X = Convert.ToDouble(point[0].Trim());
                                    double Y = Convert.ToDouble(point[1].Trim());
                                    coordinates.X = X;
                                    coordinates.Y = Y;
                                    coordinates.Z = 0;
                                    mark.coordinates.Add(coordinates);
                                }
                            }
                        }
                    }
                    if (lineString != null && lineString.Count > 0)
                    {
                        mark.typeStr = "line";
                        foreach (var p in lineString)
                        {
                            cNode = (XmlElement)p;
                            //线的样式
                            mark.style = new { LineStyleColor, LineStyleWidth };
                            var coordinatesNode = cNode.GetElementsByTagName("coordinates");
                            if (coordinatesNode != null && coordinatesNode.Count > 0)
                            {
                                string pointstr = coordinatesNode[0].InnerText;
                                var points = pointstr.Split(new char[] { '\n', ' ' });
                                var pointsCount = points.Length;
                                foreach (var item in points)
                                {
                                    var coordinates = new Coordinates();
                                    var pointStr = item.Trim();
                                    if (string.IsNullOrEmpty(pointStr))
                                    {
                                        continue;
                                    }
                                    var point = pointStr.Split(',');
                                    double X = Convert.ToDouble(point[0].Trim());
                                    double Y = Convert.ToDouble(point[1].Trim());
                                    coordinates.X = X;
                                    coordinates.Y = Y;
                                    coordinates.Z = 0;
                                    mark.coordinates.Add(coordinates);
                                }
                            }
                        }
                    }
                    if (linearRing != null && linearRing.Count > 0)
                    {
                        mark.typeStr = "ring";
                        foreach (var p in linearRing)
                        {
                            cNode = (XmlElement)p;
                            var coordinatesNode = cNode.GetElementsByTagName("coordinates");
                            if (coordinatesNode != null && coordinatesNode.Count > 0)
                            {
                                string pointstr = coordinatesNode[0].InnerText;
                                var points = pointstr.Split(new char[] { '\n', ' ' });
                                var pointsCount = points.Length;
                                foreach (var item in points)
                                {
                                    var coordinates = new Coordinates();
                                    var pointStr = item.Trim();
                                    if (string.IsNullOrEmpty(pointStr))
                                    {
                                        continue;
                                    }
                                    var point = pointStr.Split(',');

                                    double X = Convert.ToDouble(point[0].Trim());
                                    double Y = Convert.ToDouble(point[1].Trim());
                                    coordinates.X = X;
                                    coordinates.Y = Y;
                                    coordinates.Z = 0;
                                    mark.coordinates.Add(coordinates);
                                }
                            }
                        }
                    }
                    retMarks.Add(mark);
                }
            }
            return retMarks;
        }

        /// <summary>
        /// 获取KML桩号坐标集合
        /// </summary>
        /// <param name="filePath">路径</param>
        /// <returns></returns>
        public static List<Placemark> GetStakeCoordinate(string filePath)
        {
            List<string> list = new List<string>();
            List<Placemark> retMarks = new List<Placemark>();
            if (!File.Exists(filePath))
            {
                return new List<Placemark>();
            }
            if (Path.GetExtension(filePath).ToLower() == ".kmz")
            {
                list = UnZip(filePath, Path.GetDirectoryName(filePath));
            }
            else
            {
                list.Add(filePath);
            }
            foreach (var path in list)
            {
                XmlDocument xmldoc = new XmlDocument();
                xmldoc.Load(path);
                //申明xml命名空间管理对象
                XmlNamespaceManager nsmanager = new XmlNamespaceManager(xmldoc.NameTable);
                XmlElement root = xmldoc.DocumentElement;
                //添加命名空间
                nsmanager.AddNamespace("XX", "" + root.NamespaceURI + "");
                /////规范命名空间
                XmlNode t = root.GetElementsByTagName("Kml")[0];
                XmlNode _document = root.GetElementsByTagName("Document")[0];
                XmlNodeList xmlmark = xmldoc.SelectNodes("//XX:Placemark", nsmanager);
                //var isselect = false;
                foreach (XmlElement element in xmlmark)
                {
                    Placemark mark = new Placemark();
                    mark.points = new List<double>();
                    string note = string.Empty;
                    var nameNode = element.GetElementsByTagName("name");
                    if (nameNode != null && nameNode.Count > 0)
                    {
                        //string nmNode = nameNode[0].InnerText.Trim();
                        //note = Regex.Replace(nmNode, "[ \\[ \\] \\^ \\-_*×――(^)|'$%~!@#$…&%￥—+=<>《》!！??？:：•`·、。，；,.;\"‘’“”-]", "").ToUpper();
                        note = nameNode[0].InnerText.Trim();
                    }
                    mark.name = note;
                    // if (name.Contains(mark.name) || isselect)
                    //{
                    //if (!isselect)
                    //{
                    //    mark.name = name;
                    //}
                    XmlElement cNode = null;
                    var pointNode = element.GetElementsByTagName("Point");
                    if (pointNode != null && pointNode.Count > 0)
                    {
                        mark.typeStr = "point";
                        cNode = (XmlElement)pointNode[0];
                    }
                    if (cNode != null)
                    {
                        var coordinatesNode = cNode.GetElementsByTagName("coordinates");
                        if (coordinatesNode != null && coordinatesNode.Count > 0)
                        {
                            string pointstr = coordinatesNode[0].InnerText.Trim();
                            var points = pointstr.Split(',');
                            double X = Convert.ToDouble(points[0].Trim());
                            double Y = Convert.ToDouble(points[1].Trim());
                            mark.points.Add(X);
                            mark.points.Add(Y);
                            mark.points.Add(0);
                            retMarks.Add(mark);
                        }

                    }
                }
            }
            return retMarks;
        }

    }
}